"""本文件包含应用程序的身份验证工具。"""

import re
from datetime import (
    UTC,
    datetime,
    timedelta,
)
from typing import Optional

from jose import (
    JWTError,
    jwt,
)

from app.core.config import settings
from app.core.logging import logger
from app.schemas.auth import Token
from app.utils.sanitization import sanitize_string
from app.core.external_auth import external_auth_client

def create_access_token(thread_id: str, expires_delta: Optional[timedelta] = None) -> Token:
    """为线程创建新的访问令牌。

    Args:
        thread_id: 对话的唯一线程 ID。
        expires_delta: 可选的过期时间增量。

    Returns:
        Token: 生成的访问令牌。
    """
    # 如果提供了过期时间增量，则使用它计算过期时间
    if expires_delta:
        expire = datetime.now(UTC) + expires_delta
    else:
        # 否则使用默认的过期天数计算过期时间
        expire = datetime.now(UTC) + timedelta(days=settings.JWT_ACCESS_TOKEN_EXPIRE_DAYS)

    # 准备要编码到JWT中的数据
    to_encode = {
        "sub": thread_id,  # 主题，这里是线程ID
        "exp": expire,     # 过期时间
        "iat": datetime.now(UTC),  # 签发时间
        "jti": sanitize_string(f"{thread_id}-{datetime.now(UTC).timestamp()}"),  # 添加唯一令牌标识符
    }

    # 使用配置的密钥和算法编码JWT
    encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)

    # 记录令牌创建日志
    logger.info("token_created", thread_id=thread_id, expires_at=expire.isoformat())

    # 返回包含访问令牌和过期时间的Token对象
    return Token(access_token=encoded_jwt, expires_at=expire)


async def verify_token(token: str) -> Optional[str]:
    """验证访问令牌。

    Args:
        token: 要验证的令牌。

    Returns:
        Optional[str]: 如果令牌有效则返回线程 ID，否则返回 None。
    """
    # 检查令牌是否为空或不是字符串类型
    if not token or not isinstance(token, str):
        # 记录令牌格式无效警告日志
        logger.warning("token_invalid_format")
        # 抛出值错误异常
        raise ValueError("Token must be a non-empty string")

    # 在尝试解码之前进行基本格式验证
    # JWT令牌由3个用点分隔的base64url编码段组成
    if not re.match(r"^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$", token):
        # 记录令牌格式可疑警告日志
        logger.warning("token_suspicious_format")
        # 抛出值错误异常
        raise ValueError("Token format is invalid - expected JWT format")

    # 首先尝试验证外部认证系统的令牌（如果启用）
    if settings.EXTERNAL_AUTH_ENABLED:
        external_payload = await external_auth_client.verify_token(token)
        if external_payload:
            # 如果外部令牌有效，提取用户信息
            user_id = external_payload.get("sub")
            if user_id:
                # 记录外部令牌验证成功日志
                logger.info("external_token_verified", user_id=user_id)
                # 返回用户ID
                return user_id
    else:
        logger.debug("external_auth_skipped_due_to_disabled_setting")

    # 如果外部验证失败或未启用，尝试本地验证（向后兼容）
    try:
        # 使用配置的密钥和算法解码JWT
        payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])
        # 从载荷中获取主题（线程ID）
        thread_id: str = payload.get("sub")
        if thread_id is None:
            # 记录令牌缺少线程ID警告日志
            logger.warning("token_missing_thread_id")
            # 返回None表示验证失败
            return None

        # 记录令牌验证成功日志
        logger.info("token_verified", thread_id=thread_id)
        # 返回线程ID
        return thread_id

    except JWTError as e:
        # 记录令牌验证失败错误日志
        logger.error("token_verification_failed", error=str(e))
        # 返回None表示验证失败
        return None